﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using Microsoft.Practices.Unity;
using System.ServiceModel.Channels;

namespace WDA.Core
{
   /// <summary>
   /// Service host factory implementation for WCF.
   /// </summary>
   public sealed class WcfServiceHostFactory : IServiceHostFactory
   {
      private readonly Binding _binding;

      /// <summary>
      /// Creates new instance of <see cref="WcfServiceHostFactory"/>.
      /// </summary>
      /// <param name="binding">WCF binding to use.</param>
      public WcfServiceHostFactory(Binding binding)
      {
         _binding = binding;
      }

      #region IServiceHostFactory Members
      public IDisposable CreateServiceHost(string serviceName, Type serviceContract, Type serviceImplementation, Uri publishUrl, IUnityContainer localContainer)
      {
         return new WcfServiceHost(serviceName, serviceContract, serviceImplementation, publishUrl, _binding, localContainer);
      }
      public IDisposable CreateMonitorHost(Type monitorContract, object monitorImplementation, Uri publishUrl)
      {
         return new WcfMonitorHost(monitorContract, monitorImplementation, publishUrl, _binding);
      }
      #endregion

      private sealed class WcfMonitorHost : IDisposable
      {
         private bool _disposed;
         private readonly ServiceHost _realHost;

         public WcfMonitorHost(Type monitorContract, object monitorImplementation, Uri publishUrl, Binding binding)
         {
            _realHost = new ServiceHost(monitorImplementation);

            ServiceBehaviorAttribute remoteBehavior = _realHost.Description.Behaviors.Find<ServiceBehaviorAttribute>();
            remoteBehavior.UseSynchronizationContext = false;
            remoteBehavior.IncludeExceptionDetailInFaults = true;
            remoteBehavior.InstanceContextMode = InstanceContextMode.Single;

            _realHost.AddServiceEndpoint(monitorContract, binding, publishUrl);
            _realHost.Open();
         }

         #region IDisposable Members
         public void Dispose()
         {
            if (!_disposed)
            {
               _realHost.Close();
               _disposed = true;
            }
         }
         #endregion
      }

      private sealed class WcfServiceHost : IDisposable
      {
         private bool _disposed;
         private readonly ServiceHost _realHost;

         public WcfServiceHost(string serviceName, Type serviceContract, Type serviceImplementation, Uri publishUrl, Binding binding, IUnityContainer localContainer)
         {
            _realHost = new ServiceHost(serviceImplementation);
            
            ServiceBehaviorAttribute remoteBehavior = _realHost.Description.Behaviors.Find<ServiceBehaviorAttribute>();
            remoteBehavior.IncludeExceptionDetailInFaults = true;
            remoteBehavior.UseSynchronizationContext = false;

            ServiceEndpoint endpoint = _realHost.AddServiceEndpoint(serviceContract, binding, publishUrl);
            endpoint.Behaviors.Add(localContainer.BuildUp(new ManagedEndpointBehavior(serviceName)));
            _realHost.Open();
         }

         #region IDisposable Members
         public void Dispose()
         {
            if (!_disposed)
            {
               _realHost.Close();
               _disposed = true;
            }
         }
         #endregion
      }
   }
}
